home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
JCSM Shareware Collection 1993 November
/
JCSM Shareware Collection - 1993-11.iso
/
cl720
/
qbnws33j.lzh
/
QBNWS303.NWS
< prev
next >
Wrap
Text File
|
1992-11-15
|
107KB
|
2,270 lines
Volume 3, Number 3 November 15, 1992
**************************************************
* *
* QBNews *
* *
* International QuickBASIC Electronic *
* Newsleter *
* *
* Dedicated to promoting QuickBASIC around *
* the world *
* *
**************************************************
The QBNews is an electronic newsletter published by Clearware
Computing. It can be freely distributed providing NO CHARGE is charged
for distribution. The QBNews is copyrighted in full by Clearware
Computing. The authors hold the copyright to their individual
articles. All program code appearing in QBNews is released into the
public domain. You may do what you wish with the code except
copyright it. QBNews must be distributed whole and unmodified.
You can write The QBNews at:
The QBNews
P.O. Box 507
Sandy Hook, CT 06482
Copyright (c) 1992 by Clearware Computing.
The QBNews Page i
Volume 3, Number 3 November 15, 1992
----------------------------------------------------------------------
T A B L E O F C O N T E N T S
1. Beginner's Corner
Compiling and Linking Made Easy by Arthur Shipkowski ......... 1
2. DataBASICs
PDT to the Rescue! by Frederick Volking ...................... 6
Announcing PDT -- The Pro~Formance Data Tool ................. 12
3. Graphic's Workbench
Dumping Graphics Screens to your Printer by Stephen K. Gartrell 14
4. Communications Shack
Implementing XModem in QB by Bryan Leggo ..................... 19
5. Feature Presentation
Customizing EGA or VGA TEXT-MODE Fonts By Rob Smetana ........ 26
The QBNews Page ii
Volume 3, Number 3 November 15, 1992
----------------------------------------------------------------------
B e g i n n e r ' s C o r n e r
----------------------------------------------------------------------
Compiling and Linking Made Easy by Arthur Shipkowski
To start off, let me say that this is the first time I've written
about programming for beginners, or, to rephrase, I'm a beginner at
writing beginner's articles. <GRIN> Sorry about the bad pun.
To be honest, I wrote this article a little for myself, because I
don't have a BC/LINK commandline reference.
Compiling from the command line is easier than is sounds or looks,
based on the QuickBasic manual.
The BC commandline is:
BC sourcefile [,[objectfile],[listfile]] [optionlist] [;]
What does all this idiotic stuff mean? Here goes nothing. The
sourcefile is your source, not neccesairly with extention, unless
you're compiling a source file with an extention other than .BAS.
Objectfile is the name of the object file. If you don't enter this,
it will have a default of sourcefile.OBJ. However, if you don't enter
a object file, you'll be prompted for one, as you will for listfile.
List file is a listing of the source, with some info. It's normally
useless except for with the /A switch below. The default is Nul.Lst,
which will output no list file.
The Options are: (For QB 4.5)
/a - Assembler source in the list file
/ah - Array Huge! Allows big arrays, and sometimes prevents odd
errors.
/c:n - set COM buffer size to 'n' bytes. The default if 512 bytes,
sufficient for most applications except file transfers and
high baud rates.
/d - error checking when running, and Ctrl-Break will break out
of the program. This will also catch overflow errors. However,
it tends to make your program HUGE!
/e - enable ON ERROR checking with RESUME linelabel. Doesn't really
bloat code unless you use line numbers.
/mbf - Use MS binary format numbers (faster, but less accurate) instead
of IEEE.
If you don't understand this switch, you don't need it.
Anyways, there are similar conversion functions built in.
/o - Stand Alone .EXE (No BRUN needed!)
The QBNews Page 1
Volume 3, Number 3 November 15, 1992
/r - Store arrays in row-major order (Used for array passing to
languages like C and Pascal)
/s - No String compression (like string constants are not put
together) This serves two functions: A. If you have no like
string constants, this will reduce .EXE size slightly. Else, it
will bloat your .EXE. Also, this switch will sometimes stop
compiler memory errors. (It's a bit of a magic switch, like
/ah.)
/t - Terse - no compiler headers, or error messages
/v - ON EVENT check EVERY STATEMENT. Bloats your code.
/w - ON EVENT check EVERY LABEL; good if you use labels
judiciously, otherwise bloats code like /w
/x - Allows RESUME Next; bloats code like /v
/zi - Codeview support for using CodeView
/zd - SYMDEB debugger support (SYMDEB came with MASM 4.0. You
probably will never need to use this switch.)
Special options availible in BASIC PDS 7.1:
/fpa \ These switches let you decide whether or not to use an
/fpi / alternate floating point math library. /fpi
(/FloatingPointIEEE) is the default. It includes a portion
that on startup, looks for a coprocessor, and either uses or
not uses the coprocessor. This library is more accurate, but
is slower, and requires more memory becuase even if a
coprocessor is present, the other routines to fake a
coprocessor are still loaded into your precious RAM.
/fpa (/FloatingPointAlternate) is the other one. It doesn't
check for a coprocessor, and is faster but less accurate.
/fs - Enable Far Strings. This gives you more string space, but any
ASM libraries you use must support it, or you'll get WIERD
results. If you don't understand it, like /mbf, don't bother:
It's probably not worth your time anyways.
/g2 - Generate code that runs only on 286s and above. This will
provide a modest improvement is code size.
/i? - ISAM options. ISAM stands for Indexed Sequential Access
Method. If you don't understand this one, don't fret unless
you're writing a database application in PDS using the ISAM
that's built in.
The various options are:
/ie:memoryneeded - Reserve memoryneeded of EMS memory for
ISAM buffers.
/ib:twokbuffers - Reserve twokbuffers of 2 kilobyte buffers
The QBNews Page 2
Volume 3, Number 3 November 15, 1992
for accessing the EMS.
/ii:filebuffers - Reserve filebuffers number of file buffers
for file access. This switch is only needed
if you are going to use more than 30
indexes.
/lp \ Normally, BC compiles your program based on what OS it is
/lr / running under - DOS for DOS, OS/2 1.3 for OS/2. These switches
override that assumption. /lr is for compiling Real Mode (DOS)
programs under OS/2, and /lp is for compiling Protected Mode
(OS/2) programs under DOS.
/ot - Optimizes calls. Use it if you have PDS unless you can't use it
due to some add-on library. This switch basically doesn't put
a safeguard in for when you use GOSUB in a sub unless you have
a GOSUB in a SUB. (Just use it, and it will be fine)
/z - Microsoft Editor support for allowing you to find the lines
where mistakes are. Don't use it unless you're using ME,
becuase it bloats code big-time.
Now, for linking.
The LINK commandline is:
LINK [/options] objectfile [objectfile] [libfile.lib] [[[, [exefile]]
, [mapfile]], [libfile] [libfile] [;]
And what is this jibberish, you may ask? It's all rather simple, like
the compiler. The options are just those options you want (see below),
the objectfile is the name of the objectfile produced by the compiler,
as are the objectfiles in brackets. (yes, there can be more than one.)
Also, if a library contains only those routines that you want in the
.EXE, you can put it where the first libfile.lib is, otherwise put it
where the second libfile is. The exefile is only the name of the .EXE,
and is assumed to be the name of the first object file. The mapfile is
a relatively (in my opinion) useless, although it can be used to
determine DGROUP usage. The final semicolon is not required, and I'm
not exactly sure why it's there.
LINK Options: (For LINK, only the capitalized letters are neccesary,
even though you can type in the whole option name.)
/BAtch - Tells LINK it's being run from a batch file, and that it
shouldn't pause and ask you for libraries, but show a
warning message instead. Not terribly useful, even in batch
files, because one misplaced slash will bring everything
crashing down.
/COdeview - Tells LINK to include Codeview information in the .EXE.
must be used with the /zi switch in BC.
/Exepack - Tells LINK to use a form of executable compression,
similar to PKLite or Lzexe or Diet. If you have Lzexe,
The QBNews Page 3
Volume 3, Number 3 November 15, 1992
PKLite, or Diet, it's not worthwhile, since they will
compress the .EXE better than EXEPACK.
/Farcalltranslate - A optimizing switch that will reduce program size
due to LINK figuring out if a near call will work
in place of a farcall. However, in a rare case it
may malfunction if you use ON GOTO or any other
ON command. If it does, omit this switch.
Otherwise, use it.
/HElp - Tells LINK to display a list of all command switches
availible. Useful when you forget what the switches are.
/INFo - Tells LINK to display a log of activity on your screen. It
displays library routine names and object file names. Not
terribly useful.
/LInenum - Tells LINK to include information for the SYMDEB debugger,
in conjunction with the /zd switch in BC. Not terribly
useful in most cases, since SYMDEB is an old debugger
.
/Map - Tells LINK to add public symbol names to your map file, as well
as segment names. Not particularly useful for BASIC
programming.
/NOExtdict - If you have two or more procedure (SUB/FUNCTION) or data
names the same, tells LINK to use the first one it
finds, and also tells LINK not to issue an error
message. Don't use when unneccesary, because it makes
LINK run slower.
/NOFarcall - Tells LINK not to translate farcalls. This is the
default, so this switch is only useful when you have an
environment variable with default being /F.
/NOLogo - Tells LINK not to display its copyright notice.
/NOPackcode - Like /NOF, tells LINK not to pack code, is the default,
and isn't useful unless you have an environment
variable with /PACKC as the default.
/Overlayint - Tells LINK to use a different interrupt number for the
overlay manager. (Don't know why this is in QB, since
it doesn't have the rest of the overlay code, but it's
in there anyways.) Not useful unless you have some
unusual cards/adapters/software in your computer.
/PACKCode - Tells LINK to try and squish nearby sections of code
together. Most useful in conjunction with /F.
/PAUse - Tells LINK to pause and allow you to insert a disk before
writing the .EXE, for use when you're on a floppy-only
system with limited space.
The QBNews Page 4
Volume 3, Number 3 November 15, 1992
/Quicklib - Used to create a Quick library. (A bit off topic for this
article, but it may be covered in a later article.)
/SEGments: - This switch tells LINK to allocate memory for the
specified number of segment names after the colon. By
default, LINK reserves room for 128 segments. If you get
a 'Too many segments error', try increasing this number.
Don't worry about not giving LINK enough room for the
rest of the program - if it needs it, it will make a
swapfile for that stuff. (Gee, why doesn't it make a
swapfile for the segments? I don't know...)
/STACK: - Lets you set the amount of memory for stacks for a program
without using CLEAR. If you have PDS, however, the STACK
statement is a better choice.
The only LINK Option that's in PDS ONLY:
/NODefaultlib - Tells LINK not to use the library name embedded in
the object file. (i.e. BRT71EFR.LIB). Accepts a colon
after itself with the replacement library name.
To compile a program:
BC MYPROG
LINK MYPROG
To compile a standalone program:
BC MYPROG /O
LINK MYPROG
Mind you, you can add other options. Those shown above are the
absolute minimum that you need.
All of the information presented in this article (and more) can be
found in Ethan Winer's excellent book, "Basic Techniques and
Utilites." (Couldn't underline it - oh well.) I don't mean to sound
like an advertisement, but his book has an entire chapter on
compiling, linking, and making libraries, as well as chapters on alot
of other stuff.
Bibliography
Winer, Ethan. "Basic Techniques and Utilities". Emeryville:
Ziff-Davis Press, 1991
*********************************************************************
Arthur Shipkowski is a 15 year old who is the author of HackChek and
a few other PD and freeware programs. He may be reached at
1:260/213.2 in FidoNet, 041/002 in GT-Net, or at 75:7716/101 in
DoorNet.
*********************************************************************
The QBNews Page 5
Volume 3, Number 3 November 15, 1992
----------------------------------------------------------------------
D a t a B A S I C s
----------------------------------------------------------------------
PDT to the Rescue! by Frederick Volking
I must tell you up-front that I HATE doing this. A few years ago I
wrote a program that we've sold commercially in markets all over the
world. But I'm here to recommend that you try a DIFFERENT program:
the Pro~Formance Data Tool, or PDT.
I've been working with data files for over 18 years: all sizes,
shapes, formats and kinds. I can't count the number of times I've had
to write a Q-&-D (Quick-&-Dirty) program to bail myself (or a
colleague) out of situations like these:
- You're handed a new task that requires managing someone else's
data files, files with a structure you don't understand.
- During a download, several records get corrupted.
- While creating a file, NULL characters are accidentally introduced.
- A file has one field too many; or fields are too wide or too short.
- As you're developing or updating a program, something goes wrong
and you screw up a 15 megabyte data file.
- You're developing a data file and find you have to mass-edit
several thousand records.
So what do you do? Write another program to examine the data file?
To fix corrupted data? To edit records? Yeah, sure: The blind
leading the blind. Wouldn't it be nice to have a utility to directly
view ANY file, to examine the data IN THE RAW, to change it on the
fly, to figure out its structure, then edit it to your liking!
Every time I had to write a new program, I wished someone would invent
an editor whose only job was to help me VIEW, UNDERSTAND or EDIT ANY
file, in a simple, logical, structured way. I looked around for
utilities to handle these tasks. I found several that let me view
files, or edit one type of file. But I never found one that let me
view, interrogate, format and edit ANY file: simply and easily.
So I gave up looking and wrote my own. I wrote it mainly for my own
use; but others took note, and a software distributor picked it up and
began marketing it commercially under the name of DFD (the Data File
Doctor).
Although I wrote DFD, I've always known it was a rather crude Q-&-D
solution. So after almost 3 years of limping along with DFD, I
finally found another product that does everything DFD should have
done. The program is called PDT (the Pro~Formance Data Tool). It's
offered by Rob Smetana of Pro~Formance in San Francisco, California.
The QBNews Page 6
Volume 3, Number 3 November 15, 1992
PDT directly competes with my DFD product. But that's okay because,
frankly, I save more $$$ using PDT (in time and effort) than I make
from DFD. That says a lot!
Overview
--------
Very simply, PDT is a wonder to behold! It offers features no other
program does; it has everything DFD should have had. And perhaps most
important for some, you can try-it-before-you-buy. PDT is a shareware
program you can find on CompuServe, America-On- Line and many large
Bulletin Boards. You may also contact the author to get a copy: Rob
Smetana, at (415) 863-0530.
PDT is an extremely flexible tool to view and edit ANY file --
including files on networked drives, floppy drives and hard disks.
Using PDT I've edited tiny 0 and 1 byte files as well as huge, 970
megabyte files residing on a networked 1 gigabyte Novell file server.
(PDT can edit files up to 2 gigabytes in size!)
PDT's speed is nothing less than phenomenal. Working across the
Novell network, I changed the first byte in this 970 megabyte file,
then jumped to the end of the file and changed the last byte. The
total elapsed time was 15 seconds -- on a networked drive!
Data File Editing
-----------------
PDT's data file editing tools are unmatched in any program.
For example, if you open a dBase ".DBF" file, PDT automatically
formats your view of the data into logical rows and columns.
Many programs can do this. But PDT is unique not only in the long
list of other features it offers, but also in letting you use this
same intelligence with virtually ANY fixed-length data file, like
those created by most programming languages. PDT can remember
field-by- field layouts for your data files, and then display that
data in rows and highlighted columns -- automatically, as you open the
file!
- You can tab from field to field to easily edit data.
- As you move the cursor to a field, PDT displays the "value"
of that field -- even fields stored in packed binary format.
- And you can easily edit even packed binary numeric fields.
PDT automatically converts the binary number to it's decimal
equivalent, lets you edit it and reconverts the edited value
back to the binary equivalent before saving it to disk.
Here are some examples of the kind of things I've done with PDT:
The QBNews Page 7
Volume 3, Number 3 November 15, 1992
- We created a new dBase file to store incoming ASCII data. After
the data was merged, I found several fields were much wider than
necessary. I just moved to the fields, told PDT to shrink them,
and in seconds it was done -- across thousands of records, saving
millions of bytes of disk space. PDT even updated the dBase file
header automatically. And PDT can do this just as easily with
non-dBase data files.
- I needed to copy several hundred records to a new file. Using
PDT's Block Mark and Block Export features it took 10 seconds!
- We download a 300 megabyte file from the mainframe. But we soon
discovered it had been damaged in transit. I opened it in PDT,
set the record length, and within seconds had found the damaged
area. It took just 1-2 minutes to restore the damaged data and
we were on our way -- without writing a line of code.
- I needed to merge records from one data file into the middle of
another. I opened both files in PDT (PDT lets you open 4 file
windows simultaneously), marked the block I wanted to copy,
jumped to the other file window and selected "Copy/Insert."
PDT merged the new records instantly.
- We were handed a data file we had to analyze, but had no idea
what the file structure was. I opened it in PDT, made a guess
as to the record length, then leaned on the F9 and F10 keys.
When you press F9 or F10, PDT adjusts the record length up or
down, and re-draws the screen to adjust it's "view" of the
data. The data literally swings into the proper view.
Once we figured out the record length, it was easy to identify
where each field began, and what type of field it was (ie.,
character, integer, double, currency, etc.). For each field,
we pressed a key and told PDT what the field name and field type
were. When we were done, PDT saved a "structure file" to disk.
This structure file gave us everthing we needed to create a
"structure" or "TYPE" in our programs to read the data. And
whenever we opened the file again in PDT, PDT read the structure
file and automatically formatted the data into rows and columns.
List of Features
================
The examples above just scratch the surface of what you can do with
PDT. Here's a summary of some of the 50 or so options PDT offers.
Block Options:
--------------
"Blocks" can be records, columns or a continuous stream. Once you
mark a block you can Delete it, Export it, Fill it (with any ASCII
character or phrase), Copy it (to another location in the same file,
or to another file). You can even mark a column and Add it up, or
add Sequence Numbers to it (like unique customer or part numbers).
The QBNews Page 8
Volume 3, Number 3 November 15, 1992
Search & Replace:
-----------------
Full Search and Replace functions are provided. These may occur
forwards or backwards, anywhere in the file or in just the block or
column you've marked, and can ignore Upper and Lower case. You can
Search & Replace using any ASCII character: 0 (null) through 255.
EBCDIC File Support:
--------------------
One of PDT's most unique features is its EBCDIC file-handling.
You can leave EBCDIC files on disk as-is, and tell PDT to dynamically
translate them on-the-fly into ASCII. This lets you view and edit
data in easy-to-understand ASCII format. But anything you change
is automatically converted back to EBCDIC, then saved to disk.
Or, if you prefer, PDT will translate files from EBCDIC to ASCII,
or vice versa.
File Management:
----------------
PDT lets you Create, Delete, Rename or Copy files, or create file
directories. A powerful "Join" command lets you merge up to 6
files while using the smallest amount of disk space possible.
Ease of Use; Getting Help:
--------------------------
Editing files is much like working in a word processor. PDT supports
25-, 43- and 50-line modes in full color or true monochrome. True
monochrome works fine on LCD (laptop) displays.
PDT offers both pull-down menus and fast keyboard hotkeys. And
most hotkeys are easy to remember (O = Open file, C = Close,
S = Search, etc.). PDT supports a mouse for most operations.
Online-help is available for EVERY option. Just pull down a menu,
highlight an option, then either press F1 or click the right mouse
button and a help window pops up. There's also a large, detailed
documentation file you can view from inside PDT (or print it).
Flys in the Ointment
--------------------
In short, PDT lets you view and edit virtually any file up to 2
gigabytes in size. And since you can open 4 file windows, you can
work with up to 8 gigabytes of data at once.
But PDT isn't perfect. My main gripe is that "I" didn't write it
..... Okay, I said it.
The QBNews Page 9
Volume 3, Number 3 November 15, 1992
To understand another PDT limitation, you have to know a little about
how PDT handles file editing. Unlike an editor or word pro- cessor
which loads files into memory, PDT loads NOTHING into memory. When
you open a file, you're looking at what's on disk (although PDT does
wonders formatting your view of it). This fact allows PDT to let you
view/edit 2-gigabyte files with NO need for extra memory. And it
displays files with astonishing speed.
But when you turn edit mode on (it's OFF by default) and then change
something, that change is immediately written to disk.
The fact that all changes are immediately saved accounts for PDT's
restriction that when you Replace something, you must replace it with
something else of the same length. A word processor's search and
replace function can expand or contract things in memory. But if PDT
replaced something with something else of a different width, every
time it found a "hit," PDT would have to re-write the entire disk file
from that point all the way to the end. As you can imagine, with
large files, this would be time-consuming and could be risky.
PDT's approach also means that YOU must be careful and should make
backup copies. I've NEVER seen PDT damage a file. But it gives YOU
the power to muck things up very quickly if you're not careful. If
you keep edit mode off you can't do damage. Turn edit mode on when
needed.
Other "nit piks" include:
- PDT offers a calculator offering both decimal and hexadecimal
calculations. I'd suggest that it be centered on the screen
(rather than off to the side), provide a tape readout, and
support a mouse.
- While PDT correctly translates EBCDIC characters to their
ASCII equivalent, the "values" of EBCDIC packed numeric fields
don't always translate properly. That's because translating
the values of fields requires that you know where fields are and
what type of field they are -- something PDT often doesn't know.
- You can open up to 4 file windows simultaneously, and windows can
be opened either horizontally or vertically. No problem there.
But when you close a window, PDT re-draws all the other windows
to fill in the now-empty space. In doing so it often changes
the original choice of a window's layout: horizontal/vertical.
The QBNews Page 10
Volume 3, Number 3 November 15, 1992
Summary
-------
If you're a programmer, if you create or use database files, or you
must maintain or repair data files, you should look at PDT. You'll be
amazed at it's flexibility, speed and awesome power. And since PDT is
a shareware program, you can try it out for just the cost of a
download (or a $5 disk fee from a shareware distributor).
Or, you can order it directly from:
Rob W. Smetana Pro~Formance
132 Alpine Terrace
(415) 863-0530 San Francisco, CA 94117
EDITOR'S NOTE: As a special offer to readers of the QBNews,
you can order PDT for 30% off the normal price: $69 versus $99.
This offer is good through November, 1992. And you MUST mention
the QBNews to take advantage of this offer.
The QBNews Page 11
Volume 3, Number 3 November 15, 1992
Announcing PDT -- The Pro~Formance Data Tool
Master your data and EXE files. Edit up to 8 gigabytes at once!
================================================================
We're pleased to announce the release of version 2.3 of PDT, the
Pro~Formance Data Tool. And to readers of the QBNews, we're now
offering a SPECIAL DISCOUNT OFFER, good through October, 1992.
For details see "For Information" at the end of this announcement.
PDT is a very unusual, extremely powerful file editor with tools and
features NO OTHER PROGRAM offers. It's designed for:
* programmers
* developers or users of dBase, other data files, EBCDIC files, etc.
* anyone who needs to view, edit or manage data files
* anyone who needs to determine the structure of files, or who
needs to repair corrupted files
* anyone who'd like to edit ANY file -- up to 2 gigabytes in size.
2 Gigabyte File Editor
======================
* With PDT you can view and edit ANY file: dBase files, other
data files, executable files (eg., EXE or COM files), EBCDIC
files, ASCII files, font files -- any file.
* View and edit ANY SIZE file -- up to two gigabytes! And you
can open up to 4 files at once. View and compare different
files. Or work in different areas of the same file. Since each
file can be up to two gigabytes in size, you can work with up
to 8 gigabytes of data at once!
Manage database files like you've never been able to before!
============================================================
* PDT automatically detects dBase ".DBF" files, formatting your
view of them into logical rows and columns.
* With other fixed-length data files (like those created by pro-
grams written in C, Pascal, BASIC, COBOL, etc.), PDT lets you
easily and quickly define their "structure" -- field names,
widths, types (string, integer, double, etc.).
And if you're not sure of the structure of a file, PDT can help
you quickly figure it out. PDT can even save a "structure file"
to disk -- which you can use to create the TYPE or structure
you'd need in your programs to use that file.
* Once PDT knows the structure of a file, records and fields will
be laid out in logical rows and columns. You can then easily
view/edit the file, tabbing quickly to any field. And you can:
- See values of compressed, packed binary data in easy-to-
The QBNews Page 12
Volume 3, Number 3 November 15, 1992
understand ASCII. You can even press a key to edit "packed
binary" numeric fields. Enter, say, 9,822, and PDT saves
it in the appropriate packed binary form.
- Mark blocks (either columns or records) and then: Export
them, Copy them, Delete or Fill them, etc.
- Expand or Shrink the width of fields. This feature is
incredible! Imagine moving your cursor to a database
field, then pressing a key and saying "Expand this field
10 spaces." Zap! It's done.
And PDT will even update the dBase header and its own
"structure files," if you like, to reflect the change.
* PDT even manages EBCDIC files -- like those found on, or down-
loaded from, large IBM computers. PDT can DYNAMICALLY trans-
late EBCDIC files to ASCII, letting you edit them files in easy-
to-understand ASCII mode. Changes are saved to disk in EBCDIC.
PDT can even translate EBCDIC files to ASCII format, or vice versa.
* PDT can also help you:
- Repair files -- regardless of their type or size.
- Determine file structures (record length, field structures, etc.).
- Edit executable files to update or customize messages or options.
================================================================
For information on PDT or to order, call or write Rob Smetana at:
Pro~Formance (415) 863-0530
132 Alpine Terrace San Francisco, CA 94117
Visa and MasterCard Accepted
SPECIAL 30% DISCOUNT for QBNews readers!
========================================
Through November, 1992, readers of the QBNews may order PDT for
just $69 (+ $4 shipping/handling; $8 outside the US & Canada).
This saves you 30% off the normal $99 price!
BE SURE to mention the QBNews to take advantage of this offer.
================================================================
The QBNews Page 13
Volume 3, Number 3 November 15, 1992
----------------------------------------------------------------------
G r a p h i c ' s W o r k b e n c h
----------------------------------------------------------------------
Dumping Graphics Screens to your Printer by Stephen K. Gartrell
So, you want to print a graphics screen. Well, you've got two
choices. You could leave directions to your users to load DOS's
GRAPHICS.COM before starting your program. (You could even do it
automatically, with a *.BAT file.) Then, using the QB/QBX.QLB, you
could make an INT 5 print screen call.
Piece of cake, right? But, what if your users don't have
GRAPHICS.COM? Are you going to see if, for a small fee, Microsoft
will let you distribute one of their programs with yours? (Define
"small".) Let's say that they do have it, and always remember to load
it, or that your batch file can cope with the myriad directory
structures and PATH statements out there. Are your colors going to
show up as clearly when printed as they do the way your screen routine
drew them? It seems like more control is in order...
What is a "screen" drawing? It's a series of pixels that you can't
tell apart _unless_ they are of different colors, the exact numbers of
pixels being dependent upon screen mode. What's a typical black ink
on white paper "printout"? It's a series of dots that you can't tell
apart unless they are separated by white, or non-printed, spaces.
Now, let's see about getting the one onto the other.
Printers, as a rule, are devices that expect all data to arrive one
byte at a time as ASCII. This works great for letter writing;
everyone knows that the standard ASCII set only uses 0d(ecimal) to
127d- heck, most printers can now deal with the extended ASCII set
through 255d! But trying to tell the printer to put "one dot here,
and then another one to the right and slightly down" doesn't translate
into ASCII too well.
Before I go on, a brief orientation (pun intended): "Portrait mode" is
a printout that appears as a normal letter would appear; "Landscape
mode", for all practical purposes, is printing the screen picture
"sideways" on the printer sheet.
In graphics mode, we need to set the line feed so that a column of
dots starts immediately below the column above it. We can do this by
sending an "Escape" sequence to the printer. An "ESCAPE" code, more
familiarly known as ASCII code 27, alerts the printer to the fact that
the next sequence of bytes is not ASCII, but should instead be
interpreted as control codes. In the example program, a 1/9" line
feed is used by sending 27d/51d/nd where "n" is the line feed pitch in
216ths of an inch (in this case, "n" is therefore equal to 24.)
Likewise, we must decide upon the dot density of the printout and put
the printer into graphics, or "dot-addressable", mode. Typically, an
"IBM/EPSON compatible" printer will offer four choices, namely 60 DPI
(dots per inch), 120 DPI half-speed (which will ensure good row
alignment), 120 DPI normal speed, and 240 DPI.
The QBNews Page 14
Volume 3, Number 3 November 15, 1992
When making this choice, the size of the paper, the screen resolution,
and the print orientation must be taken into consideration. We are
(arbitrarily) in SCREEN 12; this gives a 640x480 pixel resolution.
Since one printer dot will represent one screen pixel, we must divide
the horizontal ("X") pixels by our printer dot resolution to ensure
that the printout will fit into a typical 8 1/2" by 11" sheet of
printer paper. A bad choice would be 60 DPI; as 640 pixels divided by
60 "pixels"/inch means that our sheet needs to be 10 2/3" wide. So
we'll use 120 DPI half-speed (76d); we do this by sending another
"Escape" sequence to the printer. In this case, the format would be:
PRINT #printerfile%, CHR$(27); CHR$(76); CHR$(lsb); CHR$(msb);
Uh, oh! "Lsb", "msb"? We've run into that "byte at a time" printer
communications limitation, yet again. What the printer wants from the
program is "how many bytes of raw graphics data should I receive
before I start looking for control codes or ASCII characters again?".
Since we are printing the screen in "Portrait" mode, the answer (in
SCREEN 12) is 640 bytes. But, since we can only send one byte at a
time to the printer, we must break the two bytes that 640d needs down
to meet this. Thus, the "lsb" would equal 640 MOD 256, while the
"msb" would equal 640 \ 256. (While you can calculate this
beforehand, the example program makes use of a global or SHARED
variable and does it on the fly.) For the purposes of this
explanation, we'll pretend as though we'd sent a "0" msb and an "8"
lsb, since we are only going to send an 8 pixel by 8 pixel block.
So far, we've told the printer how far apart to space line feeds, what
DPI to use, and how many sequential graphics bytes to expect. Now
it's time to send the first byte. We'd better put one together!
First, let's draw a grid on the screen; in the grid will be a pixel
representation of a circle:
SCREEN 12
Screen "X"
0 1 2 3 4 5 6 7
┌─┬─┬─┬─┬─┬─┬─┬─┐
0 │ │ │ │ │ │ │ │ │ 2^7 = 128
├─┼─┼─┼─┼─┼─┼─┼─┤
1 │ │ │ │■│■│ │ │ │ 2^6 = 64
├─┼─┼─┼─┼─┼─┼─┼─┤
2 │ │■│■│ │ │■│■│ │ 2^5 = 32
├─┼─┼─┼─┼─┼─┼─┼─┤ "IBM/EPSON"
3 │■│■│ │ │ │ │■│■│ 2^4 = 16 Printer "Graphics"
Screen "Y" ├─┼─┼─┼─┼─┼─┼─┼─┤ Bit-Weighting
4 │ │■│■│ │ │■│■│ │ 2^3 = 8
├─┼─┼─┼─┼─┼─┼─┼─┤
5 │ │ │ │■│■│ │ │ │ 2^2 = 4
├─┼─┼─┼─┼─┼─┼─┼─┤
6 │ │ │ │ │ │ │ │ │ 2^1 = 2
The QBNews Page 15
Volume 3, Number 3 November 15, 1992
├─┼─┼─┼─┼─┼─┼─┼─┤
7 │ │ │ │ │ │ │ │ │ 2^0 = 1
└─┴─┴─┴─┴─┴─┴─┴─┘
IBM/EPSON compatible (that word...) printers anticipate graphics bytes
to to be "bottom up" oriented; i.e. the bottom dot of the eight
possible is 2^0 while the top dot is 2^7 (these values are
precalculated in the example program, as the call to the ^ function is
excruciatingly slow). We use POINT to get the pixel values, starting
with X,Y coordinate (0,7) and working up through the column to (0,0).
The first column only has one pixel set; it's 2^4, or 16. The next,
however, has three pixels set. To hurry things along:
Printer Byte
Column 0 = 2^4 = 16
Column 1 = 2^3 + 2^4 + 2^5 = 8 + 16 + 32 = 56
Column 2 = 2^3 + 2^5 = 8 + 32 = 40
Column 3 = 2^2 + 2^6 = 4 + 64 = 68
Column 4 = 2^2 + 2^6 = 4 + 64 = 68
Column 5 = 2^3 + 2^5 = 8 + 32 = 40
Column 6 = 2^3 + 2^4 + 2^5 = 8 + 16 + 32 = 56
Column 7 = 2^4 = 16
But, what about the colors we invested our circle with? (O.K., assume
half of it is a different color.) How do we go about conveying
"color" to the human eye on a black ink on white paper printout?
Remember, the way we can tell those dots apart to start with, is to
have "white", or non-printed, intervals between them. What we can do,
therefore, is to control the amount of dots printed for any particular
color we are interested in. We do this by ANDing our weighted pixel
bit values with a mask.
BLUE GREEN RED YELLOW
Mask # Mask # Mask # Mask #
01234567 01234567 01234567 01234567
2^7 [■■■■■■■■] [■ ■ ■ ■ ] [■ ■ ] [ ] 2^7
2^6 [■■■■■■■■] [ ■ ■ ■ ■] [ ] [ ] 2^6
2^5 [■■■■■■■■] [■ ■ ■ ■ ] [ ■ ■ ] [ ■ ] 2^5
2^4 [■■■■■■■■] [ ■ ■ ■ ■] [ ] [ ] 2^4
2^3 [■■■■■■■■] [■ ■ ■ ■ ] [■ ■ ] [ ] 2^3
2^2 [■■■■■■■■] [ ■ ■ ■ ■] [ ] [ ] 2^2
2^1 [■■■■■■■■] [■ ■ ■ ■ ] [ ■ ■ ] [ ■ ] 2^1
2^0 [■■■■■■■■] [ ■ ■ ■ ■] [ ] [ ] 2^0
&&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&&
HHHHHHHH HHHHHHHH HHHHHHHH HHHHHHHH
FFFFFFFF A5A5A5A5 80208020 00200000
FFFFFFFF A5A5A5A5 80208020 00000020
Mask Values
(Read Vertically)
The QBNews Page 16
Volume 3, Number 3 November 15, 1992
The first mask, &HFF, when ANDed with the result of testing eight
pixels for the color blue, returns all of 'em back. Obviously, this
pattern is not necessary, but adding a test in the print subroutines
to check for a need to mask the colors may slow it down. Printer
speed will be the deciding factor.
By now, you might be thinking: "Why in the world do I have to use
eight different masks for one color?". Good question. Consider the
effect of POINT finding an 8x8 pixel block of solid red. If you only
used one mask (as represented by mask zero in the third block, &H88),
then it would be printed as:
[■■■■■■■■]
[ ]
[ ]
[ ]
[■■■■■■■■]
[ ]
[ ]
[ ]
Stripes!! Through the use of MOD, however, we can cycle through all
eight masks and eliminate this effect, as the example program will
show.
You may have noted that with four mask sets, the pixels will need to
be read four times. POINT, as you may have observed in earlier
experiences, is not particularly fast. What the example program does
is read as many pixels as will be needed with a FOR/NEXT, and then
store the returned values in an array for later processing. In turn,
rather than make four printing passes, the results of each masking AND
pass are ORed into one output byte. This transfers all the necessary
output dots as expeditiously as is possible.
Now, we know what to send. How do we get it there? The easiest way
is to bypass QB/PDS and go through the BIOS using printer interrupt
&H17. Since we don't want to overwork our fingers, we'll also open
the printer as a "file" using OPEN "lpt1:BIN" FOR OUTPUT AS #filenum%.
The use of the BIN keyword in the OPEN statement means that QB/PDS
shouldn't count characters and emit a carriage return, the timing of
which we wish to control ourselves. (You may experiment, and find
that LPRINT and PRINT # fail miserably in place of the INT &H17 call
for sending actual graphics bytes.)
On to the subject of "aspect ratios". First, what is it? It's the
ratio of a screen's width to it's height. Ordinarily, your CRT has
approximately a 1.33 (4:3) aspect ratio. (Speaking of it's _physical_
dimensions.) This means that screen output tends to be distorted as a
result of being "stretched" horizontally. As a practical experiment,
PSET a 50 pixel line horizontally, and then another vertically, in
SCREEN 7. Then measure the resultant lines as they appear on your
CRT. A significant difference exists, with the horizontal line being
longer even though the number of pixels is identical. Those pixels
The QBNews Page 17
Volume 3, Number 3 November 15, 1992
must not be square, we must conclude.
Now add differing screen resolutions. In 320x200 modes, the aspect
ratio is 4.8:3; in 640x480 mode, it's back to 4:3. (Here, I'm
referring to the ratio of pixels wide to pixels high.) QB/PDS
graphics commands usually offer you the ability to adjust the aspect
ratio of graphics objects, either by passing an "aspect" value, or by
simply altering line lengths.
What happens when we print a screen? A printer dot is the same size,
period. (Pun also intended.) The aspect compensation that was done
for your screen now has an exaggerated effect at your printer. In
320x200 modes, for instance, a circle that was perfectly round on your
screen, since it was made a little taller to compensate for the extra
1.8 in pixels width to height ratio, will appear taller and skinnier
on paper in Portrait mode. Unless, as the example program does, you
adjust for it by either duplicating adjacent dots, or perhaps by
adding additional blank columns. The VidConfig function call of the
example program sets SHARED variables automatically in the event that
you wish to use aspect compensation.
One last note, and then on to the example program. Recall the
statements alluding to telling the printer "how many graphics bytes to
expect". If you should interrupt program operation before that number
has been reached, and are unable to resume printing _precisely_ where
the program left off, just go ahead and reset your computer, or cycle
power on your printer, or make a call to interrupt &H17 function &H01
(initialize printer). Otherwise, your printer will still be expecting
graphics characters, and will treat all control or ASCII characters
sent to it as graphics characters!!!
Also: Most, if not all, printers come with a manual that has the
applicable ESCAPE codes listed in an appendix. Check it out!!
Code for this article can be found in GPRINT.ZIP.
*********************************************************************
Steve Gartrell spent six years in the U.S. Army, primarily concerned
with various aspects of digital and analog communications. He obtained
an Associate's Degree in Electronics Technology from Ohio University
and has been programming in QuickBasic for the last several years,
with Assembly language enhancements as needed.
*********************************************************************
The QBNews Page 18
Volume 3, Number 3 November 15, 1992
----------------------------------------------------------------------
C o m m u n i c a t i o n s S h a c k
----------------------------------------------------------------------
Implementing XModem in QB by Bryan Leggo
XModem, far from state-of-the-art in transfer protocols, does have one
great advantage: it's simple, easy to implement and therefore
available in more places than any other. Some communications programs
may only have one or two binary protocols and XModem is usually one of
them so it's especially good to have it available if you're writing a
host program or BBS in order to reach the greatest number of users.
XMODEM.BAS is a simple terminal program with procedures to send and
receive with the XModem protocol. Three variations on the protocol are
handled within the code.
The three basic types are the original protocol (Standard), XModem CRC
and XModem-1k which is sometimes referred to as YModem (non-batch
variety). Most transfer protocols use some method of error checking to
see if the proper characters were sent and received. Standard XModem
used a Checksum, adding the bits of each byte. Next came XModem CRC
which replaced the one byte Checksum with the more accurate and
reliable 16 bit (2 bytes) CRC. The third variation, XModem-1k may use
EITHER Checksum or CRC. It is different from the others in it's block
size, i.e. that it sends 1024 file data bytes at a time instead of the
usual 128.
All variations only send so many characters at a time until it can be
verified that the transmission was complete and correct or until an
error is detected. The groupings of characters from the file being
sent are referred to as "blocks", and so we say that XModem-1k has a
block of size 1024 bytes (1k). Standard uses a block of 128 bytes. But
in addition to bytes from the file being sent we must also have some
controlling characters (the checksum being an example) to smooth the
transmission of each block. Therefore we use the term "packets" to
describe the block of file data bytes plus all necessary control
characters. The Standard XModem packet is constructed as follows
(where <xyz> denotes a single byte):
<Soh> + <Block Number> + <Complement Block Number> + Block +<Checksum>
<Soh> is Ascii Value 1, or CHR$(1) in Basic. Other common Ascii codes
that we will use include <Stx> (Ascii 02), <Ack> (Ascii 6) to
ACKnowledge, <Nak> (Ascii 21) to Negatively AcKnowledge, <Can> (Ascii
24) to CANcel and <Eot> (Ascii 4) to indicate End Of Transmission.
These are defined globally in XMODEM.BAS.
The Block Number is a single byte and thus may represent a number from
1 to 255. To further verify transmissions both Sender and Receiver
keep track of which block is being sent and this number advances
accordingly. Obviously, whether the block is 128 bytes or 1024, many
files will be large enough to require more than 255 blocks so the
Block Number will wrap to be 1 again after 255.
The QBNews Page 19
Volume 3, Number 3 November 15, 1992
The Complement Block Number is just that, (Block Number XOR 255), so
that as Block Numbers go 1, 2, 3, 4, 5.... the Complement will be 254,
253, 252, 251....
Block is the group of 128 or 1024 bytes from the file (depending on
type of XModem in use) and <Checksum> is the Checksum value of all the
bytes in that Block.
XModem is "receiver driven" which means that the receiving end
controls the flow of information by sending back characters as
signals. These signals are used to alert the sender of errors and for
timing purposes, i.e. the receiver will tell the sender when it is ok
to send the next packet (or to resend a packet with errors detected).
Not receiving data on time, called "timing out" is an error in itself
and can cause the transmission to be aborted if chronic. Timing is
used in both the process of getting each character of a packet and in
initiating the transfer, sometimes called "handshaking" here.
Handshaking can take a few seconds because Sender and Receiver operate
independently and may start at different times. The Sender waits while
the Receiver sends out the start signal every few seconds, waiting for
a response from the Sender. The starting signal is <Nak> for Checksum
and <C> for CRC mode.
Below is a diagram of typical successful Standard XModem transmission.
In this example we have an example file of say 493 bytes which would
require 4 blocks of 128 bytes, i.e. transmitting 4 packets. The
transfer is initiated by the Receiver sending a <Nak> and waiting for
a response. If no response comes within the alloted time it would send
another <Nak> until getting a response or it has reached it's maximum
number of attempts. In this example we will also say that due to line
noise one packet had a glitch in one of the block characters the first
time it was sent out, which caused an incorrect Checksum value.
Sender Receiver
------ --------
01. <--- <Nak>
02. <Soh> <1> <254> Block <ChkSum> --->
03. <--- <Ack>
04. <Soh> <2> <253> Block <ChkSum> --->
05. <--- <Ack>
06. <Soh> <3> <252> Block <ChkSum> ---> (Error Detected!)
07. <--- <Nak>
08. <Soh> <3> <252> Block <ChkSum> --->
09. <--- <Ack>
10. <Soh> <4> <251> Block <ChkSum> --->
11. <--- <Ack>
12. <Eot>
13. <--- <Ack>
The error occurred in Step 06, where the corrupted data led to an
improper checksum. So, instead of an <Ack> which would indicate the
The QBNews Page 20
Volume 3, Number 3 November 15, 1992
packet was okay, the receiver sends a <Nak> (NOT Acknowledged) in Step
07 so that the Sender will know to RE-transmit that same Block, that
is, Block 3. It does so in Step 08. The Sender doesn't know what KIND
of error it was. It could have been a Bad Block, Bad Complement Block
Number or some other error but as long as it knows to transmit the
same block again we have a good chance of recovering.
FIRST BYTE OF A PACKET, THE PACKET "HEADER"
The first byte of each packet is especially important. For a normal
Standard packet with data following it should always be <Soh> but it
also may be a <Can> to Cancel transmission in case of a "fatal" error
or an <Eot> as in Step 12 to indicate that there is no more data and
the transmission is complete. If the first byte is anything but <Soh>,
<Stx>, <Can> or <Eot> then it is an error.
Since the first byte will not necessarily be followed by block data (a
<Can> or an <Eot> are not followed by a full packet), in coding it we
will get the first byte and check what it is before going on to get
the remainder of the packet.
FATAL ERRORS
Excessive numbers of errors, even minor errors like timeouts cause a
transfer to be aborted. What is "excessive" though, may depend on the
programmer. Originally XModem retried all errors 10 times and used
varying timeout values for handshaking and character timeouts in
packets. No Carrier detected is also a fatal error. And both sender
and receiver are allowed to manually abort transmission which can be
handled by the fatal error routine.
In XMODEM.BAS a timeout occurs after 8 seconds without data and the
initial connection will be tried 10 times, first several times in CRC
mode and the remainder with Standard XModem. Up to 10 errors will be
tolerated in the transmission of packets.
XMODEM-CRC
XModem CRC differs from Standard in two ways. First in the way the
transfer is initiated. Instead of the Receiver sending a <Nak> to
indicate readiness it would send the letter C (Ascii 67). For example,
in order to try CRC Mode in the diagrammed example above then Step 01
would have the Receiver send a "C".
Since the term XModem is sometimes used loosely and it's not always
apparent whether a BBS or Comm program are supporting XModem CRC we
want implementations of CRC Mode to be downward compatible with
Standard Mode. To acheive this we have the Receiver try BOTH C and
<Nak>. In XMODEM.BAS for example we try C the first 4 times and then
try <Nak> the remaining times. If the Sender hasn't responded by that
time then it is a fatal error. You may want to modify this, or employ
another scheme, perhaps one that alternates between sending <C>s and
<Nak>s in order to speed up handshaking.
The QBNews Page 21
Volume 3, Number 3 November 15, 1992
The other difference for CRC of course, is that we replace the
Checksum byte with a CRC value. That means that a CRC packet will be
one byte longer than a Standard one since it is a 16 bit CRC and
requires two bytes, first high, then low, as illustrated below:
<Soh> <Block #> <Complement Block #> Block <CRCHighByte> <CRCLowByte>
------------- ------------
XMODEM-1K
This may be run in either Standard or CRC Mode. The difference is in
the size of the block which will be 1024 bytes, except possibly for
the final portion of a file where some blocks will be 128 bytes. More
about that below. XModem-1k must therefore be able to accept any
combination of blocks of EITHER size. That means that the sender must
have a way of notifying the receiver of which block size to
anticipate. When we are sending a block of 1024 bytes we will use
<Stx> as the first byte of the packet instead of <Soh>. In CRC Mode 1k
this would be:
<Stx> <Block #> <Complement Block #> Block <CRCHighByte> <CRCLowByte>
-----
PADDING WITH CHR$(0)
Each Block sent by XModem must be either 128 bytes or 1024 bytes. But
most file lengths will not be evenly divisible by these so on the
final block transmitted we pad with nulls if necessary. In XModem-1k
that could mean an awful lot of padding, so rather than enlarge the
file received to the nearest multiple of 1k the sender will switch to
128 byte blocks for the final part of the file. That way we will not
enlarge the file any more than the nearest multiple of 128. THAT is
why XModem-1k must be able to handle any combination of 128 or 1024
byte blocks. And depending on which size a block is, we will as usual
send a first byte of either <Soh> or <Stx> in each packet.
SETTING THE TIMEOUT LENGTH REMOTELY
Originally XModem allowed the Receiver to notify the Sender of the
Timeout value being used (in seconds), apparently for better
coordination. Looking at old XModem code it appears to me that to do
so the Receiver would send CHR$(14) + "T " followed by an Ascii String
of the timeout length, but since this is not detailed in the docs I
consulted I can't be sure. In testing and looking at the transmissions
of other BBS XModems it appears that setting a timeout value is not
usually done anyway. Ignoring the "T " + value should not cause any
problems since anything but a <Nak> or <C> can be ignored while
initiating.
XMODEM PACKETS RE-CAP
Block refers to Block of Text from File (128 bytes, 1024 for
XModem-1K) Packet Refers to Block + Extra "Control" Characters, i.e. :
The QBNews Page 22
Volume 3, Number 3 November 15, 1992
Standard: SOH + BlockCt + Complement BlockCt + Block + CheckSum
XModemCRC: SOH + BlockCt + Complement BlockCt + Block + CRC (Hi & Low)
XModem-1K: STX + BlockCt + Complement BlockCt + Block + CheckSum
CRC-1K: STX + BlockCt + Complement BlockCt + Block + CRC (Hi & Low)
** Sometimes may also use 128 byte blocks with SOH replacing STX
NOTES ABOUT THIS IMPLEMENTATION (XMODEM.BAS)
When Receiving:
Bytes in blocks of 128 received are not immediately written to disk
but are temporarily stored in an array B$(). After the 4th one, when
512 bytes total have accumulated they are all written to disk in order
to save time used in accessing the disk. This is a convention due to
CP/M's use of 512 byte disk granularity and may not be necessary on
other machines.
A Repeated Block Number is handled by the Error Warning routine even
though it is not really a serious error. If the Sender is erroneously
resending a packet that was just received without errors that means
that the <Ack> the Receiver just sent to Acknowledge it was garbled as
in Step E of of the example diagrammed below. Even though the Block
Number was not the expected one processing can continue. Since it is
not necessary to resend that packet the repeated block number and
packet are virtually ignored by the receiver and it sends an <Ack>
instead of <Nak> as in Step G below.
Sender Receiver
------ --------
A. <--- C
B. <Soh> <1> <254> Block <CRCHigh> <CRCLow> --->
C. <--- <Ack>
D. <Soh> <2> <253> Block <CRCHigh> <CRCLow> --->
E. *** Corrupted <Ack> *** <--- <Ack>
F. <Soh> <2> <253> Block <CRCHigh> <CRCLow> ---> (Repeated)
G. <--- <Ack>
H. <Soh> <3> <252> Block <CRCHigh> <CRCLow> --->
and so on....
Timeouts are measured by marking the time with TIMER and checking the
difference from the Marked Time to the current one. Crossing midnight
is usually a problem here, returning a large difference but one faulty
character timeout won't matter much in the scheme of things since the
routine will tolerate several more timeouts.
Many implementations of XModem will use different timeout values for
the initial handshaking process and later when reading packets from
the Sender. XModem documents suggest a 10 second timeout per attempt
to initiate and then going to a 1 second timeout thereafter, which
could be a bit risky with a 1,024 byte block size and a slow CRC
routine that works on full blocks (as XMODEM.BAS does).
The QBNews Page 23
Volume 3, Number 3 November 15, 1992
Whereas you might want at least 5 seconds between attempted
handshakes, a 1 second timeout for block characters would often be
fine, but I couldn't see any serious disadvantages in having a longer
packet/character timeout.
They also suggest one very long timeout of a minute for the Sender.
But since the Receiver can eventually fatally timeout itself and will
then send a <Can> to the Sender, XMODEM.BAS has no Sender timeout at
all.
When Sending:
We are using one routine to handle both 128 and 1k sized blocks so it
is easier to open the file to be sent at length 128 for both cases.
If sending 128 then we can send immediately after GETting the next
block from disk. If sending 1024 then we can GET 8 times (8 * 128 =
1024), appending each disk read to Blk$ until ready to send the entire
1024 bytes.
In CRC-1k the calculated number of TtlBlocks is based on a block size
of 1024. But since the final few packets may indeed be 128 byte blocks
this leads to situation where more packets than the value of TtlBlocks
are sent. This would give percentages greater than 100 in the display
so an extra check is added for this and the Video Bar indicating
transfer progress.
The estimated transfer time is very rough. It's based on the number of
bytes being sent per packet, Ttlblocks and Baud rate. It does not take
into account timing delays, CRC calculation time, or resends. I
experimented with an empirical approach, using a measured "average"
time per packet but these estimates were even worse! Let me know if
you find a better way to estimate.
CYCLICAL REDUNDANCY CHECK
The CRC isn't even remotely optimized. (Some things sure would be
easier if QuickBASIC had ShiftLeft and ShiftRight functions). In fact,
you can improve the speed of the CRC simply removing the FOR J loop
and explicitly writing the group of three statements within eight
times, replacing the Power(J)'s with 128,64,32,16 and so on.
As is, on my computer the CRC is fast enough and there is no danger of
it causing a timeout error. But I'm sure that linking with an external
.OBJ CRC routine or using Assembler or a table lookup approach would
be faster and may even be necessary on some slower machines. Or to be
safe you could just increase the timeout limit. You could also
calculate the CRC incrementally as each byte comes in but this would
unnecessarily complicate the TimedGet Function.
CODE STRUCTURE
I originally began this program by adapting GWBASIC code that was not
The QBNews Page 24
Volume 3, Number 3 November 15, 1992
structured in approach. Continuing to use GOTOs in the Error Handling
is partly held over from that but also not a bad idea in itself. I
rarely use them for anything but Error Handling. It's certainly better
than jumping out of a a GOSUB routine and leaving the return address
on the stack. Feel free to impose a few DO LOOPs if you're unduly
offended by them.
PROBLEMS
This program is not bulletproof. If the receiver should erroneously
receive a <Can> or <Eot> due to line noise as the first byte of a
packet it may respectively cancel transmission or prematurely close
the file. The chances of this happening are actually quite low but it
would be nice to have a surefire and standardized way to handle such
garbaged transmissions. XMODEM.BAS in the SendXModem Procedure
attempts to handle a false <Can> by looking for at least 2 more <Can>s
afterwards (where the BlockCt and Complement BlockCt would normally be
in a packet). XModem commonly uses 5 <Can>s followed by 5 <BS>s to
trigger cancellation, although many implementations will only require
one <Can>. In fact, using using CHR$(24) to Cancel is not even part of
the official standard. (Note: the purpose of the BackSpaces is to
erase the extra <Can>s if they should show on screen at the other
end.)
The PurgeBuffer routine removes any characters still waiting in COM to
be processed. Some timing has been added so that at least half a
second must also go by since the last buffered character was junked.
Only then will it return, hopefully all extraneous characters removed.
Just checking for EOF can cause problems when machine speed is so much
faster than baud rate that the loop back to the EOF test is done
before more characters can be received.
EXTERNAL PROTOCOLS
XMODEM.BAS is setup to allow easy calling of an external protocol.
Define the SendExternal$ and RecvExternal$ variables to execute the
desired program from DOS with desired parameters. Since you may need
to specify a filename you can use the tilde ( ~ ) as a placeholder for
the filename.
<ACK>-MENTS
I'd like to thank Keith Hampton for helping me down the road of ruin
called transfer protocols, without whom none of this programming would
have been necessary. He provided much info, including passing on
technical documents such as the XModem Compendium by Chuck Forsberg. I
suggest you consult that if you'd like to add YModem batch mode to
your repertoire.
The files for this article can be found in XMODEM.ZIP.
The QBNews Page 25
Volume 3, Number 3 November 15, 1992
----------------------------------------------------------------------
F e a t u r e P r e s e n t a t i o n
----------------------------------------------------------------------
Customizing EGA or VGA TEXT-MODE Fonts By Rob Smetana
Question : : :
* Have you ever wanted to replace the dull, ordinary text-mode
font your PC (or your users' PCs) normally uses?
* Would you like to be able to display different types of
messages in different fonts -- in text mode?
* Or how about special symbols: Copyright or Trademark symbols,
arrows, pointers, etc.
* Would you like to be able to tuck several text fonts into
your programs, and then just "CALL fontname" to change fonts?
If you answered "YES" to any of these questions, you'll find these
routines to change text fonts a valuable addition to your tool kit.
FontDemo.Bas
------------
If you have an EGA or VGA monitor, you might want to STOP READING
and run FontDemo.Bas. Some of the things we'll discuss below
might make more sense if you've already seen them in action. (By
the way, if, when you run FontDemo, you're curious what "P~F" and
"Pro~Formance" mean, they're our trademark and company name.)
To run FontDemo.Bas, you MUST load one of the two Quick Libraries
we included. The ".QLB" files contain text fonts we'll CALL; and
they also contain the Interrupt routines needed to invoke the BIOS
video services.
In QB: qb fontdemo /L fonts45
In QBX: qbx fontdemo /L fonts7
NOTE QB 4.x users: Before running FontDemo, you MUST comment out
one line. Please read the comments near the top of FontDemo.
ALSO NOTE: FontDemo contains some routines you may find useful
even if you don't need to change text fonts:
QB.Monitor helps you determine the type of monitor is being
used -- AND the number of screen rows (25/43/50).
SideLogo displays a scrolling banner -- in 4 directions.
Changing Fonts: EGA or VGA Required, and Text-Mode Only
--------------------------------------------------------
The QBNews Page 26
Volume 3, Number 3 November 15, 1992
Note that monochrome, CGA and Hercules monitors simply can't
change text-mode fonts using the routines we'll describe. Their
hardware doesn't support it. We've seen no harm done by trying
to switch fonts on these monitors. But nothing happens.
Also, we're talking about changing text-mode fonts -- those used
by DOS, QB.Exe or QBX.Exe, many editors and word processors,
spreadsheets, etc. While it's possible to use the same fonts
we'll discuss here in graphics mode, we won't be covering that.
One advantage of using custom fonts in graphics mode is you can
use many different fonts on the same screen. And these fonts
can vary in size -- from tiny to huge.
In text mode however, 2 character sets may be active at once (al-
though you can re-map parts of each character set to obtain many
different fonts). And the size of text-mode fonts is, in general,
limited to the size of the "character cell" (each character appears
in a cell or grid that's usually 8 dots wide and either 16, 14 or 8
dots high). So in text mode we have a limited amount of space to
work in, which constrains how large text characters can be (al-
though you can use 2 or more characters to "piece together" larger
symbols or letters. For an example, note the large "P~F" logo dis-
played when you run FontDemo.Bas).
(Note: Well discuss how to change the basic text font here. Our
TextFont Programmer's Edition offers ASM routines to let you display
two different fonts at the same time AND MANY different mouse cursor
shapes -- arrows, hour glasses, and many others -- in text mode!)
Your Possibilities Still Abound
-------------------------------
But even with just one character set available in text mode, you
still have many options.
For example, you can re-map just certain characters (like control
codes or high ASCII characters) and then print these to create
unusual effects. And you can re-map these characters several
different times in your program -- the appearance of all other
characters remains constant. At the beginning of your program,
re-map Chr$(255) to display a Copyright symbol. Later, re-map
Chr$(255) to display a pointer.
FontDemo.Bas illustrates printing Chr$(255) and control charac-
ters to display Copyright and Registered Trademark symbols, and
a "pointing hand" text-mode cursor. It also illustrates using
high ASCII characters to print text sideways, upside down,
underlined or in Italics -- while we're printing normal text
in normal ways!
You can also display text and then quickly switch fonts. As you
switch fonts, the appearance of the on-screen text changes -- the
screen is NOT cleared. FontDemo.Bas also has examples of this.
The QBNews Page 27
Volume 3, Number 3 November 15, 1992
What you need
-------------
To replace the standard text font on EGA/VGA monitors you need 2
things, and a 3rd is desirable.
1. First you need fonts. We've included some here; and we also
included a small, "freeware" font editor with which you can
design your own fonts. Later, we'll mention some other sources.
2. You need the code to do it. That's the easy part.
3. Desirable is a RAM-resident TSR that's able to restore your
font when programs change screen modes.
- Once you change fonts, any change in screen modes (to,
say, graphics mode or to 43- or 50-line mode) will restore
the default font. So if you're working in a spreadsheet
with your new font, and view a graph, the TSR should
restore your text-mode font when you return to text mode.
- Later we'll explain how one might go about developing this
TSR. (We send one to registered users of the TextFont pro-
gram we recently released. TextFont offers about 50 fonts!)
Switching Fonts: The Basics
----------------------------
Changing text mode fonts is quite simple. We'll illustrate two
ways to do it:
1. By loading fonts from disk.
- This option lets you keep many font files on disk (or in a
font library, or concatenated to the end of EXE files).
Storing fonts on disk lets you keep EXE sizes small, while
giving you access to dozens or hundreds of alternatives.
2. By CALLing fonts by name (eg., CALL Script), using the ASM
files that Font2Asm can create for us.
- This option is easy and fast; it's ideal when you need few
font changes, or when you want to re-map just a few charac-
ters. And since you'll assemble the ASM files and LINK the
OBJ fonts to your programs, this option minimizes the
chances that on-disk font files will get lost or damaged.
Changing Fonts: Using the BIOS Video Services
----------------------------------------------
Regardless of whether you load fonts from disk or CALL FontName,
the actual work of changing fonts is done by a BIOS video service
often called the Character Generator Routine.
The QBNews Page 28
Volume 3, Number 3 November 15, 1992
* All BIOS video functions are accessed via Interrupt 10h.
* The service (function) we want (the Character Generator) is 11h.
* For more information on these services, consult Ralph Brown's
interrupt guides, or works by Norton or Duncan.
To change fonts, we simply need to:
1. Determine several things about the font we want to load:
- How many characters we want to re-map (1 to 256).
- How wide each character's bit-map is (usually 8, 14 or 16).
- And where (ie., beginning with which ASCII character) we
want to begin re-maping characters.
2. Invoke Int 10h, service 11h.
That's it! And please notice two things about step #1:
* WE specify how many characters we'll re-map (replace), which
gives us tremendous flexibility. We can replace all ASCII
characters, just 1-2 characters, or anything in between.
- All of the examples you'll see if you run FontDemo.Bas
re-map just part of the 256 character ASCII set. For
example, many examples re-map just the English language
characters -- Chr$(33) to Chr$(126). We did NOT re-map
the line-draw characters, since that's often unnecessary
and undesirable (doing so can cause gaps in lines), and
this helped us keep font files small.
* WE specify which characters we want to re-map.
- You can re-map some of the 256 ASCII characters you'll never
use in your programs. For example, in FontDemo.Bas, we re-
mapped some control characters and some high ASCII characters.
This let us print normal text in normal ways, and ALSO print
text sideways, upside down, underlined and in italics.
-- To print underlined text, we simply loaded underlined
versions of A-Z and a-z into the "slots" normally reserved
for ASCII characters 128 and beyond.
-- Then, to print a normal "A" we printed "A." To print an
underlined "A," we printed Chr$(129) -- whose ASCII code
was 64 higher than the normal "A."
How to Load Fonts From Disk
---------------------------
Keeping fonts in disk files (or font libraries) gives you access
to dozens or hundreds of different fonts. We included two font
The QBNews Page 29
Volume 3, Number 3 November 15, 1992
files: Italics.14 and Uline.14 (underlined).
Here's how we loaded the Italics font in FontDemo.Bas.
* All the hard work is done by a subroutine in FontDemo called
LoadFontFile. To load a font, just CALL LoadFontFile, speci-
fying which on-disk file to use, and describing the font.
* We mentioned earlier that to load a font we must know several
things about that font:
- How many characters we want to re-map (1 to 256).
Both of our sample font files contain 64 characters --
basically just the English language A-Z and a-z. So step
#1 is to indicate how many characters we'll be loading:
NumberChars = 64
- How wide each character's bit-map is (usually 8, 14 or 16).
In our sample fonts, each character is represented by
14-byte strings. They correspond to an 8 x 14 character
cell which is useable on BOTH EGA and VGA monitors.
CharWidth = 14
- And where (ie., beginning with which ASCII character) we
want to begin re-maping characters.
Many font files you find on BBSs (or those you create with
VGAFONT.COM) contain all ASCII characters from 0 to 255. To
load one of these, you'd indicate that the 1st character to
re-map is Chr$(0). When you CALL LoadFontFile, you'd set
FirstChar = 0.
But in both Italics.14 and Uline.14, the first character is
"@" --- ASCII character 64. If we wanted to replace normal
characters with Italic versions, we'd set FirstChar = 64.
Then all English-language text would be displayed in Italics.
However, in FontDemo.Bas we wanted to be able to display
BOTH normal AND Italic text. So we loaded Italics.14 into
characters 128 and beyond -- 64 higher than our 1st character.
FirstChar = 128
* In summary, our CALL to LoadFontFile looks something like this
(we'll explain the parameter "UsingFarStrings" shortly):
FontFile$ = "ITALICS.14"
NumberChars = 64
CharWidth = 14
The QBNews Page 30
Volume 3, Number 3 November 15, 1992
FirstChar = 128
Call LoadFontFile (FontFile$, CharWidth, FirstChar, _
NumberChars, UsingFarStrings)
Here's what you'll find if you examine LoadFontFile:
1. First we read the font file in one gulp.
FontFile = FREEFILE
OPEN FontFile$ FOR BINARY AS #FontFile
a$ = SPACE$(LOF(FontFile)) ' read entire font in one gulp
GET #FontFile, , a$ ' do it
CLOSE #FontFile
2. Next, since we'll be invoking a BIOS interrupt by CALLing
InterruptX, we must translate our numeric variables into
a form InterruptX can handle.
- Near the top of FontDemo we created a TYPE called
RegTypeX. It consists of several integer variables
corresponding to the "registers" one must often set
up before invoking BIOS or DOS functions. (Earlier
issues of the QBNews have discussed CALL INTERRUPT;
so we won't belabor the point here.)
- We then dimensioned this TYPE, declaring it SHARED so
all routines in FontDemo had access to it.
DIM SHARED Registers AS RegTypeX
- So, before invoking our BIOS function, we set up the
appropriate registers. Here's a summary of what's
needed to switch fonts.
CX -- # of characters you're loading (1 - 256)
DX -- ASCII code of 1st character to remap (0 - 255)
BH -- # of bytes in each bit-map (eg., 8, 14, 16)
BL -- block to load (0)
ES:BP pointer to the string/array containing your font
Once we set up the registers, we invoke interrupt 10h,
function 11h TWICE -- once to load our font, and then
to set it (or to select it, or to turn it on).
Here's how we set up the call to InterruptX in LoadFontFile.
The QBNews Page 31
Volume 3, Number 3 November 15, 1992
Registers.CX = NumberChars ' # of characters in the font
Registers.DX = FirstChar ' DX = where to begin loading.
' This is the ASCII # of the
' character where you want to
' begin loading your font. It
' is often 0 or 33 or 128 or ???
' NOTE: FirstChar + NumberChars should never exceed 256!
Registers.BX = CharWidth * 256 ' BH = # of bytes in each
' character's bit map (eg., 8,
' 14, 16). Since we must set BH,
' we multiply CharWidth by 256.
' BL (block to load) will be 0
- Next, we point ES:BP to the Segment and Address of the
string containing our font data. THIS is where the
parameter "UsingFarStrings" comes into play.
-- If you're using QBX (or compiling using BC7's FAR
string option) you's use SSEG to determine the
segment in which the font string (a$) resides.
-- But in QB (or if you're compiling using BC7's NEAR
string option), you'd use VARSEG to get the segment.
IF UsingFarStrings THEN
Registers.ES = SSEG(a$) ' Segment if using QBX/BC7 FAR strings
ELSE
Registers.ES = VARSEG(a$) ' Segment w/ QB or BC7's NEAR strings
END IF
Registers.BP = SADD(a$) ' The address of our string
3. Finally, we invoke interrupt 10h TWICE: first to LOAD the
font, and then to SET it.
Registers.AX = &H1100 ' Use Function 11h, Service 0 (Load)
' of Interrupt 10h.
' AH = 11h - The function we want
' AL = 0 - Load user font
InterruptX &H10, Registers, Registers ' Invoke BIOS service 10h
The QBNews Page 32
Volume 3, Number 3 November 15, 1992
Registers.AX = &H1103 ' Use Function 11h, Service 3 (Set)
' AH = 11h - The function we want
' AL = 3 - Set (Select) our font
Registers.BX = 0 ' BL = Which block to load (parallels
' what we did above when loading it)
InterruptX &H10, Registers, Registers ' Invoke BIOS service 10h
That's it! Any text that's currently on your screen will now
appear in the new font. The screen will NOT clear, although
you might see it "twitch." That's because these BIOS functions
DO cause a screen-mode set, but without clearing the screen.
What Could Go Wrong
-------------------
If your screen suddenly turns into unreadable gibberish, it may
be because:
* The font file did NOT exist on disk. Who knows what was loaded.
* You erred when specifying one of the parameters (eg., you said
each bit map was 14-bytes when it was really 16). In this case
characters might be readable, but each may have pieces of the
previous (or next) character.
* The "UsingFarStrings" parameter was wrong. (eg., you were
working in QBX, but then compiled using the NEAR string option).
This would point to the wrong area of memory; and again, who
knows what you're looking at.
Since errors like this can turn everything unreadable -- including
what you see in QB/QBX -- you might want to put SCREEN , 0 near the
top of programs you're developing. This helps ensure QB/QBX restore
the default font when you return to the environment. Also get
familiar with CALL RestoreDefault (MonitorType).
CALLing FontName; Creating CALLable Fonts
---------------------------------------------------------------
An even easier way to change text fonts is to LINK them to your
programs and then just CALL FontName! To do this:
* Create (or find) some font files (see "Sources of Fonts" below).
* Run Font2Asm.Bas. CORRECTLY answer each question it asks you.
Font2Asm is not included here.
* Font2Asm will create an ".ASM" file (with the name you
specify). Assemble this ".ASM" file using MASM 5.1 + to
create an ".OBJ" file.
The QBNews Page 33
Volume 3, Number 3 November 15, 1992
* You can then use LIB and LINK to:
- Add this ".OBJ" to LIB files:
LIB FONTS +ITALICS;
- Add them to your Quick Libraries:
LINK /Q/SEG:512 ITALICS, , NUL, BQLB45; (or QBXQLB with PDS)
- Or LINK them to your programs:
LINK MYPROG, , NUL, BCOM45 + FONTS (+ other LIB files);
LINK MYPROG, , NUL, BCL71ENR + FONTS (+ other LIB files);
When you "CALL FontName," you're actually doing the same thing
that LoadFontFile does -- it's just easier and it looks different.
For example, here's part of SYMBOLS.ASM created by Font2Asm:
Mov CX, 10 ;# of characters in our font
Mov DX, 14 ;starting character (we're re-
;mapping control characters here)
Mov BH, 16 ;# bytes per character
Xor BL, BL ;block to load (0)
Mov AX, CS ;Load ES:BP with font's Segment:Offset
Mov ES, AX ;get code segment
Mov BP, Offset SYMBOLSData ;and our address
Mov AH, 11h ;LOAD font using function 11h,
Xor AL, AL ;service 0
Push BP ;Int 10 can trash BP on some PCs
Int 10h
Pop BP
Mov AH, 11h ;Now SELECT (set) the font using
Mov AL, 3 ;function 11 (in AH), svce 3 (in AL)
Xor BX, BX ;load block 0
Push BP
Int 10h
Pop BP
Ret
SymbolsData: DB 0,0,124,130,154,162,162,162,154,130,124,0,0,0,0,0
; Copyright (C)
DB 0,0,124,130,178,170,178,170,170,130,124,0,0,0,0,0
The QBNews Page 34
Volume 3, Number 3 November 15, 1992
; Registered Trademark (R)
etc . . .
Notice "SymbolsData" above. It's followed by one line of numbers
for each character we're re-mapping ("DB" is analogous to BASIC's
DATA statement). Each number is the ASCII code for a character.
Why not use strings? Because MASM (like QB/QBX) chokes when
certain characters appear in files. When you assemble this file,
each line will be converted to the same character bit-map that
appeared in the original font file. Also note there are 16
numbers on each line -- corresponding to "Mov BH, 16 ;# bytes
per character" that appeared earlier.
Eliminating Fluff; Why 14-point VGA fonts?
-------------------------------------------
Most on-disk font files you'll find, including those created by
VGAFONT.COM, may contain lots of unnecessary fluff. For example,
VGAFONT's files are 4096 bytes (16 times 256). They include
Chr$(0) and Chr$(255) which are blank. Unless you edit these,
why replace blanks with blanks?
And if you examine the character bit maps, you'll find that most
characters have "white space" around them (Chr$(0)). When you
print characters, this white space accounts for the spacing
between letters in words, and the space between lines. It's
not until you get to the high ASCII characters (especially line
drawing ASCII 176 and beyond) that the characters start to fill
the entire character cell -- so lines and boxes will connect.
The point is, once you decide which characters you want to re-map,
you may find you can delete characters, and also delete some of
the white space following each character. Doing so can eliminate
hundreds or thousands of bytes from your EXEs or font files. An
EASY way to do this is to let Font2Asm do its thing, then edit
the ASM files. Delete characters, then change one or more of the
parameters (# of characters, starting character, # bytes/character).
That's why our fonts contained 14-byte bit maps, even though they
work fine on VGA monitors with 8x16 character cells. We just
eliminated the trailing white space. Since we weren't re-mapping
control codes or line-draw characters (which DO require 16-byte bit
maps for VGA use), we were free to eliminate the excess baggage.
Sources of Fonts
----------------
We included a "freeware" program (VGAFONT.COM) you can use to
create or edit font files (if you have a VGA monitor). VGAFONT.DOC
explains how to use it.
When run, VGAFONT looks for a file called VGAFONT.DTA. If found,
VGAFONT loads it and lets you edit it. Therefore, if you have
The QBNews Page 35
Volume 3, Number 3 November 15, 1992
other font files, just rename them VGAFONT.DTA and then run VGAFONT
to edit them.
Fonts you edit with VGAFONT MUST have 16-byte bit maps. If they
don't, this small program can read, say, 14-byte bit maps, and
save them to another file, padding each character with Chr$(0).
Defint A-Z
Open "Italics.14" For Binary as #1
Open "VGAFONT.DTA" For Binary as #2
FontIn$ = String$(14, 0) '...change "14" as appropriate
FontOut$ = String$(16, 0) '...be sure to use "0" here, not "32"
Do Until EOF (1)
Get #1 , , FontIn$
Lset OutFont$ = FontIn$
Put #2 , , FontOut$
Loop
Close
You may already have several files that contain fonts. For
example, DOS often comes with files like GRAFTABL.COM or EGA.CPI
that contain fonts (although they're not very interesting). Your
word processor, spreadsheet or Windows may also include font files.
Please be aware that many of these fonts are copyrighted. So your
use of their contents may be constrained.
There are also several public domain programs that include fonts.
Try your local BBS or CompuServe. Scan for EGA*.* and VGA*.*.
Maintaining Fonts Despite Screen-Mode Changes
---------------------------------------------
We mentioned earlier that once you change fonts, any change in
screen modes (to, say, graphics mode or to 43- or 50-line mode)
will restore the default font.
You can't prevent this from happening, but you can use a TSR to
restore YOUR choice of text fonts when you return to text mode or
25-line mode. (We send such a TSR to registered users of the
TextFont program we recently released.)
You can create this TSR in many languages including BASIC (eg.,
by using Crescent's PDQ). Here's the general design:
1. Before going resident, your TSR loads a font into, say, a
string variable you'll later use to restore YOUR font.
2. After going resident, your TSR watches for a screen-mode
change to text mode. If detected, it re-loads your font.
The QBNews Page 36
Volume 3, Number 3 November 15, 1992
Specifically, you'd:
- Trap Int 10h, Function 0h (Set Video State).
- If you detect a "Set Text Mode" (eg., AL = 3h or 7h),
restore the font. SUB LoadFontFile in FontDemo.Bas has
the BASIC code you'd need to restore the font. Modify it
to point to the string variable you loaded earlier.
That's it. Such a TSR can even work in Windows. For example, when
we open a DOS window, our TSR restores the font we selected.
All files for this article can be found in TEXTFONT.ZIP.
*********************************************************************
Rob Smetana holds a Ph.D. in Organizational Psychology and runs
Pro~Formance, a firm that not only provides organizational consult-
ing but also develops software.
Among the 25+ programs they offer are TextFont (with 50+ alternatives
to the default EGA/VGA text font), P-Screen (a QB/PDS screen-design
and screen-library system that was reviewed in an earlier QB News),
P~F Presents (a presentation program often used for prototyping
programs, program demos, tutorials, training, etc.), PDT (the
Pro~Formance Data Tool, designed to help you view and edit any
file, especially dBase or any other fixed-length data files --
like font files!), and The Printer (a programmers' utility with
printer codes for over 700 different printers).
Rob can be reached at (415) 863-0530, on CompuServe (72117,1360),
or on the FidoNet Quik_Bas echo.
*********************************************************************
The QBNews Page 37